home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d1 / fmat.arc / FMAT.PAS < prev    next >
Pascal/Delphi Source File  |  1988-03-19  |  16KB  |  488 lines

  1.   {
  2.   Demonstrates formatting a floppy disk from Turbo Pascal.
  3.   This version only formats DSDD 9 sector floppies (360KB).
  4.   Works with DOS 2.0 or 3.0 in either 360K or 1.2M drives.
  5.   Does not support a /S option.
  6.   Supports a /N or -N option that turns off the verify after format.
  7.   Turn off verify step and obtain a 2x speedup vs. DOS format.
  8.  
  9.   Requires Turbo version 3.0 to compile. Compile with Minheap=Maxheap=$200.
  10.   Requires a cloning procedure after being compiled to a .COM file.
  11.   The cloning procedure copies the boot sector of an already-formatted
  12.   floppy into the program, where it can be used thereafter. To clone,
  13.   call the program as follows:
  14.  
  15.   FMAT @ <enter>
  16.  
  17.   Written 10/26/85. Kim Kokkonen, TurboPower Software.
  18.   Compuserve 72457,2131. (408)-378-3672.
  19.   }
  20.  
  21. PROGRAM fmat;
  22.     {-format a disk, DSDD 9 sectors per track only}
  23.   TYPE
  24.     {holds sector data during sector setup after formatting}
  25.     SectorBuffer = ARRAY[1..512] OF Char;
  26.     {same size as sector buffer but easily initialized in code segment}
  27.     FakeSectorBuffer = RECORD
  28.                          l, h : STRING[255];
  29.                        END;
  30.     FormatRecord = RECORD
  31.                      cyl, hed, rec, num : Byte;
  32.                    END;
  33.     FormatArray = ARRAY[1..18] OF FormatRecord;
  34.     DiskBaseRec = RECORD
  35.                     unk1, unk2, mtr, bps, eot, gpl,
  36.                     dtl, glf, fbf, hst, mst : Byte;
  37.                   END;
  38.     DiskBasePtr = ^DiskBaseRec;
  39.     registers = RECORD
  40.                   CASE Integer OF
  41.                     1 : (ax, bx, cx, dx, bp, si, di, ds, es, flags : Integer);
  42.                     2 : (al, ah, bl, bh, cl, ch, dl, dh : Byte);
  43.                 END;
  44.     FATtable = ARRAY[0..1023] OF Byte;
  45.  
  46.   CONST
  47.     {bootrecord is customized after the .COM file is created.
  48.     call FMAT with a single command line parameter '@' as follows:
  49.     FMAT @ <Enter>. This will fill in bootrecord with a real boot record}
  50.     BootRecord : FakeSectorBuffer = {fill in with bootrecord}
  51.     (l : ''; h : '');
  52.  
  53.   VAR
  54.     reg : registers;
  55.     SB : SectorBuffer;        {will fill in with dir sectors}
  56.     BR : SectorBuffer ABSOLUTE BootRecord;
  57.     VB : ARRAY[1..9] OF SectorBuffer; {will use for fast verify}
  58.     FMT : FormatArray;
  59.     FAT : FATtable;
  60.     drName : STRING[2];
  61.     param : STRING[10];
  62.     drive, dType : Byte;
  63.     ch : Char;
  64.     doVerify : Boolean;
  65.     BiosDiskBase : DiskBasePtr ABSOLUTE 0 : $78;
  66.     OldDiskBase : DiskBasePtr;
  67.     i, error : Integer;
  68.     tavail : Integer;
  69.     bavail : Real;
  70.  
  71.   PROCEDURE BIOSreadSectors(funct, drive : Byte;
  72.                             sector, track, head : Integer;
  73.                             sects : Integer;
  74.                             VAR buffer;
  75.                             VAR error : Integer);
  76.       {-execute int 13 to read disk or verify via BIOS at low level}
  77.     BEGIN
  78.       reg.ax := (funct SHL 8) OR sects;
  79.       reg.dl := drive;
  80.       reg.dh := head;
  81.       reg.ch := track AND 255;
  82.       reg.cl := (sector AND 63) OR ((track SHR 8) SHL 6);
  83.       reg.es := Seg(buffer);
  84.       reg.bx := Ofs(buffer);
  85.       Intr($13, reg);
  86.       IF Odd(reg.flags AND 1) THEN
  87.         error := reg.ax SHR 8
  88.       ELSE
  89.         error := 0;
  90.     END {biosreadsectors} ;
  91.  
  92.   PROCEDURE BIOSwriteSectors(drive : Byte;
  93.                              sector, track, head : Integer;
  94.                              sects : Integer;
  95.                              VAR buffer : SectorBuffer;
  96.                              VAR error : Integer);
  97.       {-execute int 13 to write disk via BIOS at low level}
  98.     BEGIN
  99.       reg.ax := $300 OR sects;
  100.       reg.dl := drive;
  101.       reg.dh := head;
  102.       reg.ch := track AND 255;
  103.       reg.cl := (sector AND 63) OR ((track SHR 8) SHL 6);
  104.       reg.es := Seg(buffer);
  105.       reg.bx := Ofs(buffer);
  106.       Intr($13, reg);
  107.       IF Odd(reg.flags AND 1) THEN BEGIN
  108.         error := reg.ax SHR 8;
  109.         WriteLn('error during format...');
  110.         Halt;
  111.       END ELSE
  112.         error := 0;
  113.     END {bioswritesectors} ;
  114.  
  115.   PROCEDURE InitBoot;
  116.       {-self-customize this program to hold the boot record}
  117.     VAR
  118.       ch : Char;
  119.       error : Integer;
  120.       f : FILE;
  121.       tries : Byte;
  122.  
  123.     FUNCTION CodeSize : Integer;
  124.         {thanks to Bob Tolz and Randy Forgaard for this function}
  125.       VAR
  126.         i : Byte;
  127.       BEGIN
  128.         i := 11;
  129.         WHILE NOT((Mem[DSeg-2 : i+3] <> $00E9) AND (MemW[DSeg-2 : i+4] = $0000)) AND
  130.         NOT((MemW[DSeg-2 : i+0] = $00E9) AND (MemW[DSeg-2 : i+2] = $E800)) DO
  131.           i := i+1;
  132.         CodeSize := ((((DSeg-2)-CSeg) SHL 4)+i+6)-$100
  133.       END {CodeSize} ;
  134.  
  135.     BEGIN
  136.       WriteLn('You will now clone a copy of the boot record into this program...');
  137.       WriteLn('The completed version will be written to FMAT.COM');
  138.       Write('Place a DOS formatted disk in drive A: and press any key when ready ');
  139.       Read(Kbd, ch);
  140.       WriteLn;
  141.       {read the boot record}
  142.       tries := 0;
  143.       REPEAT
  144.         tries := Succ(tries);
  145.         BIOSreadSectors(2, 0, 1, 0, 0, 1, BR, error);
  146.       UNTIL (error = 0) OR (tries = 3);
  147.       IF error <> 0 THEN BEGIN
  148.         WriteLn('could not read boot record');
  149.         Halt;
  150.       END;
  151.       {clone this program}
  152.       Assign(f, 'FMAT.COM');
  153.       Rewrite(f, 1);
  154.       BlockWrite(f, Mem[CSeg : $100], CodeSize);
  155.       Close(f);
  156.       Halt;
  157.     END {initboot} ;
  158.  
  159.   FUNCTION DOSversion : Byte;
  160.       {-return the major version number of DOS}
  161.     BEGIN
  162.       reg.ah := $30;
  163.       MsDos(reg);
  164.       DOSversion := reg.al;
  165.     END {dosversion} ;
  166.  
  167.   FUNCTION ATmachine : Boolean;
  168.       {-return true if machine is AT class}
  169.     VAR
  170.       machtype : Byte ABSOLUTE $FFFF : $000E;
  171.     BEGIN
  172.       ATmachine := (machtype = $FC);
  173.     END {ATmachine} ;
  174.  
  175.   PROCEDURE readDASD(drive : Byte; VAR dType : Byte);
  176.       {-read dasd for DOS 3}
  177.       {-whatever dasd is!}
  178.     BEGIN
  179.       reg.ah := $15;
  180.       reg.dl := drive;
  181.       Intr($13, reg);
  182.       IF Odd(reg.flags AND 1) THEN BEGIN
  183.         WriteLn('error reading DASD for format...');
  184.         Halt;
  185.       END;
  186.       dType := reg.ah;
  187.     END {readdasd} ;
  188.  
  189.   PROCEDURE setDASD(drive, dType : Byte);
  190.       {-execute int 13 to "set DASD" for format of 360K disks on 1.2MB floppies}
  191.     VAR
  192.       tries : Byte;
  193.     BEGIN
  194.       tries := 0;
  195.       REPEAT
  196.         tries := Succ(tries);
  197.         reg.ah := $17;
  198.         reg.al := dType;
  199.         reg.dl := drive;
  200.         Intr($13, reg);
  201.       UNTIL (tries = 3) OR NOT(Odd(reg.flags AND 1));
  202.  
  203.       IF Odd(reg.flags AND 1) THEN BEGIN
  204.         WriteLn('error setting DASD for format...');
  205.         Halt;
  206.       END;
  207.     END {setdasd} ;
  208.  
  209.   PROCEDURE InitFAT;
  210.       {-initialize a FAT sector}
  211.     BEGIN
  212.       {fill fat with all zeros}
  213.       FillChar(FAT, 1024, 0);
  214.       {fill in the ID Bytes}
  215.       FAT[0] := $FD;          {9 sector DSDD drive}
  216.       FAT[1] := $FF;          {boilerplate}
  217.       FAT[2] := $FF;
  218.       tavail := 80;
  219.     END {initfat} ;
  220.  
  221.   PROCEDURE InitDiskBase;
  222.       {-modify the disk base data per DOS 3 instructions}
  223.     BEGIN
  224.       {save old pointer}
  225.       OldDiskBase := BiosDiskBase;
  226.       {make a new disk base data area}
  227.       New(BiosDiskBase);
  228.       {put the data from the old area in the new one}
  229.       BiosDiskBase^ := OldDiskBase^;
  230.       {modify per dos 3 instructions, doesn't hurt on DOS 2}
  231.       BiosDiskBase^.glf := $50;
  232.       BiosDiskBase^.eot := 9;
  233.     END {initdiskbase} ;
  234.  
  235.   PROCEDURE Format(drive : Byte; VAR FMT : FormatArray; VAR error : Integer);
  236.       {-lay down format tracks}
  237.     VAR
  238.       i : Integer;
  239.     BEGIN
  240.       {initialize format table}
  241.       FOR i := 1 TO 9 DO
  242.         WITH FMT[i] DO BEGIN
  243.           cyl := 0;           {cylinder number, will fill in during format}
  244.           hed := 0;           {head number}
  245.           rec := i;           {sector number}
  246.           num := 2;           {indicates 512 bytes per sector}
  247.         END;
  248.       FOR i := 1 TO 9 DO
  249.         WITH FMT[i+9] DO BEGIN
  250.           cyl := 0;           {cylinder number, will fill in during format}
  251.           hed := 1;           {head number}
  252.           rec := i;           {sector number}
  253.           num := 2;           {indicates 512 bytes per sector}
  254.         END;
  255.       {write the format information}
  256.       INLINE(
  257.         $8A/$56/$0C/          {MOV    DL,[BP+0C] - get drive number}
  258.         $C4/$5E/$08/          {LES    BX,[BP+08] - get pointer to format array}
  259.         $B9/$01/$00/          {MOV    CX,0001 - track 0 sector 1}
  260.  
  261.         {nexttrack: - loop over 40 disk tracks}
  262.         $8B/$FB/              {MOV    DI,BX - index into format array}
  263.         $B0/$12/              {MOV    AL,12 - number of sectors per track = 18}
  264.  
  265.         {inittrack: - loop over 18 sectors per track}
  266.         $26/$88/$2D/          {MOV    ES:[DI],CH - track track number in format array}
  267.         $81/$C7/$04/$00/      {ADD    DI,0004}
  268.         $FE/$C8/              {DEC    AL}
  269.         $75/$F5/              {JNZ    inittrack}
  270.  
  271.         $B6/$00/              {MOV    DH,00 - format 9 sectors on side 0}
  272.         $B8/$01/$05/          {MOV    AX,0501}
  273.         $CD/$13/              {INT    13}
  274.         $72/$18/              {JB     error - check for errors}
  275.  
  276.         $B6/$01/              {MOV    DH,01 - format 9 sectors on side 1}
  277.         $B8/$01/$05/          {MOV    AX,0501}
  278.         $53/                  {PUSH    BX}
  279.         $81/$C3/$24/$00/      {ADD    BX,0024}
  280.         $CD/$13/              {INT    13}
  281.         $72/$0A/              {JB     error - check for errors}
  282.  
  283.         $5B/                  {POP    BX}
  284.         $FE/$C5/              {INC    CH - next track}
  285.         $80/$FD/$28/          {CMP    CH,28}
  286.         $75/$D2/              {JNZ    nexttrack}
  287.  
  288.         $31/$C0/              {XOR    AX,AX - no errors, return 0}
  289.  
  290.         {error:}
  291.         $C4/$7E/$04/          {LES    DI,[BP+04]}
  292.         $26/$89/$05           {MOV    ES:[DI],AX - return error code}
  293.         );
  294.     END {format} ;
  295.  
  296.   PROCEDURE Verify(drive : Byte; VAR FAT : FATtable; VAR error : Integer);
  297.       {-verify that sectors were formatted}
  298.     VAR
  299.       t, h : Integer;
  300.       cluster, fatofs, topcluster, content : Integer;
  301.     BEGIN
  302.       {initialize the verify buffer - 9 sectors * 512 bytes}
  303.       FillChar(VB, 4608, $F6);
  304.       {verify all sectors}
  305.       FOR t := 0 TO 39 DO
  306.         FOR h := 0 TO 1 DO BEGIN
  307.           BIOSreadSectors(4, drive, 1, t, h, 9, VB, error);
  308.  
  309.           IF error <> 0 THEN BEGIN
  310.             {mark the clusters on this track as unavailable}
  311.             cluster := ((9*(h+2*t)) DIV 2)-4;
  312.             topcluster := cluster+5;
  313.             WHILE cluster < topcluster DO BEGIN
  314.               fatofs := (3*cluster) DIV 2;
  315.               {get a word from the FAT}
  316.               Move(FAT[fatofs], content, 2);
  317.               {replace 12 bits of the word}
  318.               IF Odd(cluster) THEN
  319.                 content := content OR $FF70
  320.               ELSE
  321.                 content := content OR $0FF7;
  322.               {store it back}
  323.               Move(content, FAT[fatofs], 2);
  324.               cluster := Succ(cluster);
  325.             END;
  326.  
  327.             {reduce the number of tracks available}
  328.             tavail := Pred(tavail);
  329.           END;
  330.         END;
  331.     END {verify} ;
  332.  
  333.   PROCEDURE InitDIR;
  334.       {-initialize a sector for the root directory}
  335.     VAR
  336.       i : Integer;
  337.     BEGIN
  338.       {fill with format bytes}
  339.       FillChar(SB, 512, $F6);
  340.       {mark each directory entry as available}
  341.       FOR i := 1 TO 481 DO
  342.         IF ((i-1) MOD 32) = 0 THEN SB[i] := #0;
  343.     END {initdir} ;
  344.  
  345.   BEGIN
  346.  
  347.     doVerify := True;
  348.  
  349.     {get the drive and doverify option}
  350.     IF ParamCount = 0 THEN BEGIN
  351.       Write('Enter drive to format: ');
  352.       ReadLn(drName);
  353.     END ELSE BEGIN
  354.       {read the command line parameters}
  355.       i := 1;
  356.       drName := '';
  357.       WHILE i <= ParamCount DO BEGIN
  358.         param := ParamStr(i);
  359.         CASE param[1] OF
  360.           '@' : InitBoot;     {clone the boot record into this program}
  361.           '-', '/' :          {check for options}
  362.             IF (Length(param) = 2) AND (UpCase(param[2]) = 'N') THEN
  363.               doVerify := False
  364.             ELSE
  365.               WriteLn('WARNING: unrecognized command line option ', param);
  366.         ELSE
  367.           drName := param;
  368.         END;
  369.         i := Succ(i);
  370.       END;
  371.     END;
  372.  
  373.     {make sure the bootrecord has been cloned into program}
  374.     IF BR[1] = #0 THEN BEGIN
  375.       WriteLn('You must first clone a copy of the boot record');
  376.       WriteLn('into this program. Call as FMAT @ <Enter> to clone...');
  377.       Halt;
  378.     END;
  379.  
  380.     {check for errors, should use DOS facilities to check non-removables}
  381.     IF (drName = '') OR NOT(UpCase(drName[1]) IN ['A', 'B']) THEN BEGIN
  382.       WriteLn('Drive not Specified or cannot be formatted');
  383.       Halt;
  384.     END;
  385.  
  386.     REPEAT
  387.  
  388.       {get BIOS drive number}
  389.       drive := Ord(UpCase(drName[1]))-65;
  390.  
  391.       Write('Insert new disk in drive ', Chr(65+drive));
  392.       Write(' and press <Enter> to begin formatting ');
  393.       REPEAT
  394.         Read(Kbd, ch)
  395.       UNTIL (ch = ^M);
  396.       WriteLn;
  397.  
  398.       IF ATmachine AND (DOSversion = 3) THEN BEGIN
  399.  
  400.         {get the drive type, necessary when dealing with 1.2MB drives}
  401.         readDASD(drive, dType);
  402.         IF (dType = 0) OR (dType = 3) THEN BEGIN
  403.           WriteLn('Drive is not present or non-removable');
  404.           Halt;
  405.         END;
  406.         IF dType = 2 THEN
  407.           WriteLn('Formatting 360K floppy in 1.2MB drive');
  408.  
  409.         {set the DASD type accordingly}
  410.         setDASD(drive, dType);
  411.  
  412.       END;
  413.  
  414.       Write('Formatting... ');
  415.  
  416.       {set up the disk_base table}
  417.       InitDiskBase;
  418.  
  419.       {lay down format tracks}
  420.       Format(drive, FMT, error);
  421.  
  422.       {restore the disk_base table}
  423.       BiosDiskBase := OldDiskBase;
  424.  
  425.       IF error <> 0 THEN BEGIN
  426.         WriteLn('Error during format...');
  427.         Halt;
  428.       END;
  429.  
  430.       {initialize the FATtable}
  431.       InitFAT;
  432.  
  433.       IF doVerify THEN BEGIN
  434.         {verify sectors}
  435.         Write('Verifying... ');
  436.         Verify(drive, FAT, error);
  437.       END;
  438.  
  439.       IF error <> 0 THEN
  440.         WriteLn('Bad disk, format not verified...')
  441.  
  442.       ELSE BEGIN
  443.  
  444.         Write('Writing BOOT/FAT/DIR... ');
  445.  
  446.         {write the boot record}
  447.         BIOSwriteSectors(drive, 1, 0, 0, 1, BR, error);
  448.  
  449.         {write the FAT sectors}
  450.         Move(FAT[0], SB, 512);
  451.         BIOSwriteSectors(drive, 2, 0, 0, 1, SB, error);
  452.         Move(FAT[512], SB, 512);
  453.         BIOSwriteSectors(drive, 3, 0, 0, 1, SB, error);
  454.         Move(FAT[0], SB, 512);
  455.         BIOSwriteSectors(drive, 4, 0, 0, 1, SB, error);
  456.         Move(FAT[512], SB, 512);
  457.         BIOSwriteSectors(drive, 5, 0, 0, 1, SB, error);
  458.  
  459.         {write the root directory}
  460.         InitDIR;
  461.         BIOSwriteSectors(drive, 6, 0, 0, 1, SB, error);
  462.         BIOSwriteSectors(drive, 7, 0, 0, 1, SB, error);
  463.         BIOSwriteSectors(drive, 8, 0, 0, 1, SB, error);
  464.         BIOSwriteSectors(drive, 9, 0, 0, 1, SB, error);
  465.         BIOSwriteSectors(drive, 1, 0, 1, 1, SB, error);
  466.         BIOSwriteSectors(drive, 2, 0, 1, 1, SB, error);
  467.         BIOSwriteSectors(drive, 3, 0, 1, 1, SB, error);
  468.  
  469.         {calculate bytes available on disk}
  470.         {12 sectors are used by BOOT/FAT/DIR}
  471.         bavail := 512.0*(9.0*tavail-12.0);
  472.         WriteLn('Format complete'#7);
  473.         WriteLn('Bytes Available: ', bavail : 0 : 0);
  474.  
  475.       END;
  476.  
  477.       WriteLn;
  478.       Write('Format another? (Y/N) ');
  479.       REPEAT
  480.         Read(Kbd, ch);
  481.         ch := UpCase(ch);
  482.       UNTIL (ch IN ['Y', 'N']);
  483.       WriteLn(ch);
  484.  
  485.     UNTIL ch = 'N';
  486.  
  487.   END.
  488.